package com.ywgt.system.auth;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.ywgt.system.service.impl.RestAuthorzationEntryPoint;
import com.ywgt.system.service.impl.RestfulAccessDeniedHandler;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.ObjectPostProcessor;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.builders.WebSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.web.access.intercept.FilterSecurityInterceptor;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.web.cors.CorsUtils;

@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Autowired
    private CustomerFilter customerFilter;

    @Autowired
    private CustomUrlDecisionManager customUrlDecisionManager;

    @Autowired
    private SuccessfulAuthentication successfulAuthentication;

    @Autowired
    private FailureAuthentication failureAuthentication;

    @Autowired
    private RestAuthorzationEntryPoint restAuthorzationEntryPoint;

    @Autowired
    private RestfulAccessDeniedHandler restfulAccessDeniedHandler;

    /**
     * 路径过滤，不进行拦截
     * @param web
     * @throws Exception
     */
    @Override
    public void configure(WebSecurity web) throws Exception {
        web.ignoring().antMatchers(
                "/login",
                "/logout",
                "/css/**",
                "/js/**",
                "/static/**",
                "/favicon.ico",
                "/doc.html",
                "/webjars/**",
                "/swagger-resources/**",
                "/v2/api-docs/**",
                "/druid/login.html",
                "/swagger-ui.html"
        );
    }

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        super.configure(auth);
    }

    /**
     * 主配置类
     * @param http
     * @throws Exception
     */
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.headers().frameOptions().disable();//开启页面嵌套
        //解决跨域问题。cors 预检请求放行,让Spring security 放行所有preflight request（cors 预检请求）
        http.authorizeRequests().requestMatchers(CorsUtils::isPreFlightRequest).permitAll();
        //第2步：让Security永远不会创建HttpSession，它不会使用HttpSession来获取SecurityContext
        http.cors().disable().sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS).and()
                //禁用缓存
                .headers().cacheControl();
        //第三步：关闭跨域防护
        http.csrf().disable();

        //http.csrf().ignoringAntMatchers("/druid/*");
        //第四步：指定登录的方式及url,开放登录的api
        http.cors()
                .and().formLogin().loginProcessingUrl("/login")
                .and().authorizeRequests().antMatchers("/system/user/login").permitAll()
                .and().authorizeRequests().anyRequest().authenticated()
        .withObjectPostProcessor(new ObjectPostProcessor<FilterSecurityInterceptor>() {
            @Override
            public <O extends FilterSecurityInterceptor> O postProcess(O o) {
                o.setAccessDecisionManager(customUrlDecisionManager);
                o.setSecurityMetadataSource(customerFilter);
                return o;
            }
        });
        //使用自定义认证过滤器
        http.addFilterAt(customerUsernamePasswordAuthenticationFilter(), UsernamePasswordAuthenticationFilter.class);
        //使用token拦截器,对需要认证的请求进行token验证
        http.addFilterBefore(tokenAuthFilter(),UsernamePasswordAuthenticationFilter.class);
        //自定义未授权及未登录处理器
        http.exceptionHandling()
                .accessDeniedHandler(restfulAccessDeniedHandler)
                .authenticationEntryPoint(restAuthorzationEntryPoint);
    }

    @Bean
    public ObjectMapper objectMapper(){
        return new ObjectMapper();
    }

    @Bean
    public BCryptPasswordEncoder bCryptPasswordEncoder(){
        return new BCryptPasswordEncoder();
    }

    /**
     * 自定义认证类配置
     * @return
     * @throws Exception
     */
    @Bean
    CustomerUsernamePasswordAuthenticationFilter customerUsernamePasswordAuthenticationFilter() throws Exception {
        CustomerUsernamePasswordAuthenticationFilter filter=new CustomerUsernamePasswordAuthenticationFilter();
        //过滤器对指定路径进行拦截
        filter.setFilterProcessesUrl("/system/user/login");
        //指定AuthenticationManager
        filter.setAuthenticationManager(authenticationManagerBean());
        //指定认证成功后的处理器
        filter.setAuthenticationSuccessHandler(successfulAuthentication);
        filter.setAuthenticationFailureHandler(failureAuthentication);
        //指定认证失败后的处理器
        return filter;
    }

    @Bean
    TokenAuthFilter tokenAuthFilter(){
        return new TokenAuthFilter();
    }


}
